using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Particles2011
{
    public class Game1 : Game
    {
        readonly GraphicsDeviceManager _graphics;


        Matrix _worldMatrix;
        Matrix _viewMatrix;
        Matrix _projectionMatrix;

        BasicEffect _basicEffect;
        VertexDeclaration _vertexDeclaration;
        VertexPositionColor[] _pointList;
        VertexBuffer _vertexBuffer;

        private Vector3 _cameraPosition, _cameraDirection;
        const int Points = 8;
        short[] _triangleListIndices;

        RasterizerState _rasterizerState;
       //private MouseState mouseState;
      

        public Game1()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }


        protected override void Initialize()
        {

            InitializeTransform();
            InitializeEffect();
            InitializePoints();
         
            InitializeTriangleList();


            Mouse.SetPosition(0, 0);
            //mouseState = Mouse.GetState();
            _rasterizerState = new RasterizerState {FillMode = FillMode.WireFrame, CullMode = CullMode.None};
            base.Initialize();
        }

   
        protected override void LoadContent()
        {

        }

        
        protected override void UnloadContent()
        {

        }


        private void InitializeTransform()
        {
            _cameraPosition = new Vector3(500.0f, 0.0f, 0.0f);
            _cameraDirection = new Vector3(-1, 0, 0);
            _viewMatrix = Matrix.CreateLookAt(
                _cameraPosition,
                _cameraPosition + _cameraDirection,
                Vector3.Up
                );

            //_projectionMatrix = Matrix.CreateOrthographicOffCenter(
            //    0,
            //    GraphicsDevice.Viewport.Width,
            //    GraphicsDevice.Viewport.Height,
            //    0,
            //    0.01f, 100000.0f);
            _projectionMatrix = Matrix.CreatePerspectiveFieldOfView(1, GraphicsDevice.Viewport.AspectRatio, 0.01f,
                                                                    1000000f);
        }

        
       
        private void InitializeEffect()
        {

            _vertexDeclaration = new VertexDeclaration(new[]
                {
                    new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
                    new VertexElement(12, VertexElementFormat.Color, VertexElementUsage.Color, 0)
                }
            );

            _basicEffect = new BasicEffect(GraphicsDevice) {VertexColorEnabled = true};

            _worldMatrix = Matrix.CreateTranslation(GraphicsDevice.Viewport.Width / 2f - 150,
                GraphicsDevice.Viewport.Height / 2f - 50, 0);
            _basicEffect.World = _worldMatrix;
            _basicEffect.View = _viewMatrix;
            _basicEffect.Projection = _projectionMatrix;
        }


        private void InitializePoints()
        {
            _pointList = new VertexPositionColor[Points];

            _pointList[0] = new VertexPositionColor(new Vector3(-50,-50,-50), Color.White);
            _pointList[1] = new VertexPositionColor(new Vector3(-50, 50, -50), Color.White);
            _pointList[2] = new VertexPositionColor(new Vector3(50, 50, -50), Color.White);
            _pointList[3] = new VertexPositionColor(new Vector3(50, -50, -50), Color.White);
            _pointList[4] = new VertexPositionColor(new Vector3(50, -50, 50), Color.White);
            _pointList[5] = new VertexPositionColor(new Vector3(50, 50, 50), Color.White);
            _pointList[6] = new VertexPositionColor(new Vector3(-50, 50, 50), Color.White);
            _pointList[7] = new VertexPositionColor(new Vector3(-50, -50, 50), Color.White);


            _vertexBuffer = new VertexBuffer(_graphics.GraphicsDevice, _vertexDeclaration,
                Points, BufferUsage.None);

            _vertexBuffer.SetData(_pointList);
        }
        void UpdateKeyboard()
        {
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();
            if (Keyboard.GetState().IsKeyDown(Keys.A))
            {

                _cameraPosition -= Vector3.Cross(_cameraDirection, Vector3.Up); 
            }

            if (Keyboard.GetState().IsKeyDown(Keys.D))
            {
                _cameraPosition += Vector3.Cross(_cameraDirection, Vector3.Up);               
            }
            if (Keyboard.GetState().IsKeyDown(Keys.W))
            {
                _cameraPosition += _cameraDirection;
                
            } if (Keyboard.GetState().IsKeyDown(Keys.S))
            {
                _cameraPosition -= _cameraDirection;
                
            }
            _viewMatrix = Matrix.CreateLookAt(
                    _cameraPosition,
                    _cameraPosition + _cameraDirection,
                    Vector3.Up
                    );

            _basicEffect.View = _viewMatrix;

        }
        void UpdateMouse()
        {
            Vector3 cameraChangeDirectionX=Vector3.Cross(Vector3.Up,_cameraDirection);
            Vector3 cameraChangeDirectionY=Vector3.Cross(cameraChangeDirectionX,_cameraDirection);
            cameraChangeDirectionX.Normalize();
            cameraChangeDirectionY.Normalize();
            float xCoeff = (float) (0.001*(float) Mouse.GetState().X);
            float yCoeff = (float) (0.001*(float) Mouse.GetState().Y);
            Vector3.Multiply(cameraChangeDirectionX, xCoeff);
            Vector3.Multiply(cameraChangeDirectionY, yCoeff);
            _cameraDirection += cameraChangeDirectionX + cameraChangeDirectionY;
            _cameraDirection.Normalize();
            Mouse.SetPosition(0, 0);
            
            
            _viewMatrix = Matrix.CreateLookAt(
                   _cameraPosition,
                   _cameraPosition + _cameraDirection,
                   Vector3.Up
                   );

            _basicEffect.View = _viewMatrix;

        }

        protected override void Update(GameTime gameTime)
        {
            UpdateKeyboard();
            UpdateMouse();

            base.Update(gameTime);
        }

        private void InitializeTriangleList()
        {
            const int width = 4;
            const int height = 2;

            _triangleListIndices = new short[(width - 1) * (height - 1) * 6];

            for (int x = 0; x < width - 1; x++)
            {
                for (int y = 0; y < height - 1; y++)
                {
                    _triangleListIndices[(x + y * (width - 1)) * 6] = (short)(2 * x);
                    _triangleListIndices[(x + y * (width - 1)) * 6 + 1] = (short)(2 * x + 1);
                    _triangleListIndices[(x + y * (width - 1)) * 6 + 2] = (short)(2 * x + 2);

                    _triangleListIndices[(x + y * (width - 1)) * 6 + 3] = (short)(2 * x + 2);
                    _triangleListIndices[(x + y * (width - 1)) * 6 + 4] = (short)(2 * x + 1);
                    _triangleListIndices[(x + y * (width - 1)) * 6 + 5] = (short)(2 * x + 3);
                }
            }
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

          
            foreach (EffectPass pass in _basicEffect.CurrentTechnique.Passes)
            {
                pass.Apply();

                        GraphicsDevice.RasterizerState = _rasterizerState;
                        DrawTriangleList();
       
            }
            base.Draw(gameTime);
        }
        private void DrawTriangleList()
        {
            GraphicsDevice.DrawUserIndexedPrimitives(
                PrimitiveType.TriangleList,
                _pointList,
                0,   // vertex buffer offset to add to each element of the index buffer
                8,   // number of vertices to draw
                _triangleListIndices,
                0,   // first index element to read
                6    // number of primitives to draw
            );
        }
    }
}
